﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace Model
{
    /// <summary>
    /// 环形缓冲区
    /// </summary>
    public class RingBuffer
    {
        // 环形每块的大小
        public int ChunkSize = 8 * 1024;

        // 环形队列
        private readonly Queue<byte[]> queue = new Queue<byte[]>();

        // 已经读完后的块缓存
        private readonly Queue<byte[]> cacheQueue = new Queue<byte[]>();

        public int LastIndex { get; set; }
        public int FirstIndex { get; set; }

        private byte[] lastBuffer;

        public RingBuffer()
        {
            this.AddLast();
        }

        public RingBuffer(int chunkSize)
        {
            this.ChunkSize = chunkSize;
            this.AddLast();
        }

        /// <summary>
        /// 获取Buffer总数
        /// </summary>
        public int Count
        {
            get
            {
                int c = 0;
                if(this.queue.Count == 0)
                {
                    c = 0;
                }
                else
                {
                    // （总数 - 1）* 块大小 + 写入-读取
                    c = (this.queue.Count - 1) * this.ChunkSize + this.LastIndex - this.FirstIndex;
                }
                if(c < 0)
                {
                    throw new Exception($"TBuffer count < 0: {this.queue.Count}, {this.LastIndex}, {this.FirstIndex}");
                }
                return c;
            }
        }

        public byte[] First
        {
            get
            {
                if(this.queue.Count == 0)
                {
                    AddLast();
                }
                return this.queue.Peek();
            }
        }

        public byte[] Last
        {
            get
            {
                if(this.queue.Count == 0)
                {
                    AddLast();
                }
                return this.lastBuffer;
            }
        }

        /// <summary>
        /// 在尾部添加一个缓冲区
        /// </summary>
        public void AddLast()
        {
            byte[] buffer;

            if(this.cacheQueue.Count > 0)
            {
                buffer = this.cacheQueue.Dequeue();
            }
            else
            {
                buffer = new byte[ChunkSize];
            }
            this.queue.Enqueue(buffer);
            this.lastBuffer = buffer;
        }

        /// <summary>
        /// 移除首位缓冲区
        /// </summary>
        public void RemoveFirst()
        {
            this.cacheQueue.Enqueue(this.queue.Dequeue());
        }

        public void RecvFrom(byte[] buffer,int count)
        {
            if(this.Count < count)
            {
                throw new Exception("数据不够！");
            }

            int alreadyCopyCount = 0;

            while (alreadyCopyCount < count)
            {
                // 需要读取的数量
                int n = count - alreadyCopyCount;

                // 一个缓冲块的数据，够需要读取的数据。  8192 - 8188 = 4
                if(this.ChunkSize - this.FirstIndex > n)
                {
                    Array.Copy(this.First, this.FirstIndex, buffer, alreadyCopyCount, n);
                    this.FirstIndex += n;
                    alreadyCopyCount += n;
                }
                else // 一个缓冲块的数据，不够需要读取的数据。
                {
                    Array.Copy(this.First, this.FirstIndex, buffer, alreadyCopyCount, this.ChunkSize - this.FirstIndex);
                    // 一个缓冲块，已经读完，指向下一个缓冲块。
                    alreadyCopyCount += this.ChunkSize - this.FirstIndex;
                    this.FirstIndex = 0;
                    // 当前块弹出，指向下一块。
                    this.RemoveFirst();
                }
            }
        }

        public void SendTo(byte[] buffer)
        {
            int alreadyCopyCount = 0;
            while (alreadyCopyCount < buffer.Length)
            {
                // 判断写索引到块最后位置。
                if (this.LastIndex == this.ChunkSize)
                {
                    this.AddLast();
                    this.LastIndex = 0;
                }

                // 剩下的数据
                int n = buffer.Length - alreadyCopyCount;

                // 如果缓冲中剩下个数，是够剩下的数据存放的。
                if(this.ChunkSize - this.LastIndex > n)
                {
                    // 缓冲区能方下数据，就直接放完。
                    Array.Copy(buffer, alreadyCopyCount, this.lastBuffer, this.LastIndex, n);
                    this.LastIndex += n;
                    alreadyCopyCount += n;
                }
                else
                {
                    // 缓冲区放不下数据，就放缓冲区能放下的数据。
                    Array.Copy(buffer, alreadyCopyCount, this.lastBuffer, this.LastIndex, this.ChunkSize - this.LastIndex);
                    alreadyCopyCount += this.ChunkSize - this.LastIndex;
                    this.LastIndex = this.ChunkSize;
                }
            }
        }
    }
}
